package com.llh.demo4shiro.conf.security;

import com.llh.demo4shiro.model.Authority;
import com.llh.demo4shiro.model.Role;
import com.llh.demo4shiro.model.User;
import com.llh.demo4shiro.service.RoleService;
import com.llh.demo4shiro.service.UserService;
import com.llh.demo4shiro.utils.PasswordUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 用于网页登录的realm
 * <p>CreatedAt: 2020/9/16 15:44</p>
 *
 * @author llh
 */
@Slf4j
@Component
public class WebPageRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;

    @Override
    public CredentialsMatcher getCredentialsMatcher() {
        // 密码验证器
        return (token, info) -> {
            UsernamePasswordToken userToken = (UsernamePasswordToken) token;
            String password = new String(userToken.getPassword());
            String credentials = (String) info.getCredentials();
            return PasswordUtil.match(password, credentials);
        };
    }

    @Override
    protected AuthorizationInfo
    doGetAuthorizationInfo(PrincipalCollection principals) {
        User user = (User) principals.getPrimaryPrincipal();
        List<Role> roles = userService.getRoles(user.getId());
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setRoles(
                roles.stream().map(Role::getRoleName).collect(Collectors.toSet())
        );
        List<Authority> list = roleService.getAuth(roles.stream()
                .map(Role::getId)
                .collect(Collectors.toList()));
        authorizationInfo.setStringPermissions(
                list.stream().map(Authority::getName)
                        .collect(Collectors.toSet()));

        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo
    doGetAuthenticationInfo(AuthenticationToken token)
            throws AuthenticationException {
        String username = (String) token.getPrincipal();
        Optional<User> optional = userService.findByUsername(username);
        if (!optional.isPresent())
            return null;
        return optional.map(p ->
                new SimpleAuthenticationInfo(p, p.getPassword(), null, getName()))
                .get();
    }
}
